package top.littlejiang.onlinexam.common.base;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.littlejiang.onlinexam.common.utils.JWTUtils;
import top.littlejiang.onlinexam.entity.OlexamUser;
import top.littlejiang.onlinexam.service.OlexamMenuService;
import top.littlejiang.onlinexam.service.OlexamUserService;

import java.util.Set;

/**
 * @author chen
 * @Description
 * @since 2021/1/2 16:34
 */
@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private OlexamUserService userService;
    @Autowired
    private OlexamMenuService menuService;

    /**
     * 根据token判断此Authenticator是否使用该realm
     * 必须重写不然shiro会报错
     * @param token
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }

    /**
     * 只有当需要检测用户权限的时候才会调用此方法，例如@RequiresRoles,@RequiresPermissions之类的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String token=principals.toString();
        int userId=JWTUtils.getUserId(token);
        OlexamUser user=userService.getUserById(userId);
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        //查询数据库来获取用户的角色
        info.addRole(user.getRoleSign());
        //查询数据库来获取用户的权限
        Set<String> permsSet = menuService.listPerms(user.getRoleId());
        info.setStringPermissions(permsSet);
        return info;
    }


    /**
     * 默认使用此方法进行用户名正确与否验证，错误抛出异常即可，在需要用户认证和鉴权的时候才会调用
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String jwt= (String) token.getCredentials();
        int userId= 0;
        //decode时候出错，可能是token的长度和规定好的不一样了
        try {
            userId= JWTUtils.getUserId(jwt);
        }catch (Exception e){
            throw new AuthenticationException("token非法，不是规范的token，可能被篡改了，或者过期了");
        }
        if (!JWTUtils.verify(jwt)||userId==0){
            throw new AuthenticationException("token认证失效，token错误或者过期，重新登陆");
        }
        OlexamUser user=userService.getUserById(userId);
        if (user==null){
            throw new AuthenticationException("该用户不存在");
        }
        return new SimpleAuthenticationInfo(jwt,jwt,"MyRealm");
    }
}
